﻿using System;
using System.Collections.Generic;
using System.Linq;
using Model.Repositories;
using DomenModel;
using System.Data.Entity;
using System.Linq.Expressions;
using Model.Repositories.Interfaces;


namespace Infrastructure.Repositories
{
    public class OrderRepo : IOrderCrud
    {

        /// <summary>
        /// Gets the Order by id.
        /// </summary>
        /// <param name="Id">The id.</param>
        /// <returns></returns>
        public Order GetById(long Id)
        {
            using (GeneralContext _db = new GeneralContext())
            {
                Order orderById = _db.Orders.Include("User").FirstOrDefault(p => p.OrderId == Id);
                return orderById;
            }
        }

        /// <summary>
        /// Saves the Order to data base.
        /// </summary>
        /// <param name="t">The t.</param>
        public void Save(Order t)
        {
            using (GeneralContext _db = new GeneralContext())
            {
                _db.Orders.Add(t);
                _db.SaveChanges();
            }
        }

        /// <summary>
        /// Updates the Order.
        /// </summary>
        /// <param name="t">The t.</param>
        public void Update(Order t)
        {
            using (GeneralContext _db = new GeneralContext())
            {
                Order orderById = _db.Orders.FirstOrDefault(p => p.OrderId == t.OrderId);
                orderById.Assigned = t.Assigned;
                orderById.OrderDetailses = t.OrderDetailses;
                orderById.UserId = t.UserId;
                //orderById.user = t.user;
                orderById.DateOfOrdering = t.DateOfOrdering;
                orderById.PreferibleDeliveryDate = t.PreferibleDeliveryDate;
                orderById.DeliveryDate = t.DeliveryDate;
                orderById.CreditCardId = t.CreditCardId;
                //orderById.CreditCard = t.CreditCard;
                orderById.TotalPrice = t.TotalPrice;
                orderById.Accepted = t.Accepted;
                orderById.Delivered = t.Delivered;
                orderById.Gift = t.Gift;
                _db.SaveChanges();
            }
        }

        /// <summary>
        /// Deletes the Order from data base.
        /// </summary>
        /// <param name="Id">The id.</param>
        public void Delete(long Id)
        {
            using (GeneralContext _db = new GeneralContext())
            {
                Order orderById = _db.Orders.FirstOrDefault(p => p.OrderId == Id);
                var orderDetailsesThisOrder = _db.OrderDetailses.Where(p => p.OrderId == orderById.OrderId);

                foreach (var t in orderDetailsesThisOrder)
                {
                    _db.OrderDetailses.Remove(t);
                }

                _db.Orders.Remove(orderById);
                _db.SaveChanges();
            }
        }

        /// <summary>
        /// Gets the collection of Orders.
        /// </summary>
        /// <returns></returns>
        public List<Order> GetCollection()
        {
            using (GeneralContext _db = new GeneralContext())
            {
                var orderList = _db.Orders.ToList();
                return orderList;
            }
        }

        /// <summary>
        /// Gets the Orders list by user's name.
        /// </summary>
        /// <param name="userName">Name of the user.</param>
        /// <returns></returns>
        public List<Order> GetOrderList(string userName)
        {
            
            using (GeneralContext _db = new GeneralContext())
            {
                var orders = _db.Orders.Where(p => p.user.LoginName == userName).ToList();
                return orders;

            }
        }

        /// <summary>
        /// Gets the list of Orders for pagination by condition.
        /// </summary>
        /// <param name="page">The page.</param>
        /// <param name="itemsOnPage">The items on page.</param>
        /// <param name="predicate">The predicate.</param>
        /// <param name="descending">if set to <c>true</c> [descending].</param>
        /// <returns></returns>
        public List<Order> GetListForPagination (int page, int itemsOnPage, Expression<Func<Order, string>> predicate, bool descending)
         {
             using (GeneralContext _db = new GeneralContext())
             {

                     if (descending == true)
                     {
                         var listForPagination = _db.Orders.Include("User")
                             .OrderByDescending(predicate)
                             .Where(p => p.DateOfOrdering!=null)
                             .Skip((page - 1) * itemsOnPage)
                             .Take(itemsOnPage)
                             .ToList();

                         return listForPagination;
                     }
                     else
                     {
                         var listForPagination = _db.Orders.Include("User")
                             .OrderBy(predicate)
                             .Where(p => p.DateOfOrdering != null)
                             .Skip((page - 1) * itemsOnPage)
                             .Take(itemsOnPage)
                             .ToList();

                         return listForPagination;
                     }

             }
         }

        /// <summary>
        /// Gets the list of Order for pagination with filter.
        /// </summary>
        /// <param name="page">The page.</param>
        /// <param name="itemsOnPage">The items on page.</param>
        /// <param name="predicateListSelectedField">The predicate list selected field.</param>
        /// <param name="predicateSortBy">The predicate sort by.</param>
        /// <param name="descending">if set to <c>true</c> [descending].</param>
        /// <returns></returns>
        public List<Order> GetListForPaginationWithFilter(int page, int itemsOnPage, Expression<Func<Order, bool>> predicateListSelectedField, Expression<Func<Order, string>> predicateSortBy, bool descending)
        {
            using (GeneralContext _db = new GeneralContext())
            {

                    if (descending == true)
                    {
                        var listForPagination = _db.Orders.Include("User")
                             .OrderByDescending(predicateSortBy)
                             .Where(predicateListSelectedField.Compile())
                             .Where(p => p.DateOfOrdering != null)
                             .Skip((page - 1) * itemsOnPage)
                             .Take(itemsOnPage)
                             .ToList();

                        return listForPagination;
                    }
                    else
                    {
                        var listForPagination = _db.Orders.Include("User")
                            .OrderBy(predicateSortBy)
                            .Where(predicateListSelectedField.Compile())
                            .Where(p => p.DateOfOrdering != null)
                            .Skip((page - 1) * itemsOnPage)
                            .Take(itemsOnPage)
                            .ToList();

                        return listForPagination;
                    }

            }
        }

        /// <summary>
        /// Gets the count of orders.
        /// </summary>
        /// <returns></returns>
        public long GetCountOfOrders()
        {
            using (GeneralContext _db = new GeneralContext())
            {
                long count = _db.Orders.Where(p => p.DateOfOrdering != null).Count();
                return count;
            }
        }

        /// <summary>
        /// Gets the count of orders by user name.
        /// </summary>
        /// <param name="userName">Name of the user.</param>
        /// <returns></returns>
        public long GetCountOfOrders(string userName)
        {
            using (GeneralContext _db = new GeneralContext())
            {
                long count = _db.Orders.Where(p => p.user.LoginName == userName).Count();
                return count;
            }

        }

        /// <summary>
        /// Gets the count of orders by predicate.
        /// </summary>
        /// <param name="predicate">The predicate.</param>
        /// <returns></returns>
        public long GetCountOfOrders(Expression<Func<Order, bool>> predicate)
        {
            using (GeneralContext _db = new GeneralContext())
            {
                long _i = _db.Orders.Where(predicate).Where(p => p.DateOfOrdering != null).Count();
                return _i;
            }
        }

        /// <summary>
        /// Gets the list of Order for pagination by condition.
        /// </summary>
        /// <param name="page">The page.</param>
        /// <param name="itemsOnPage">The items on page.</param>
        /// <param name="descending">if set to <c>true</c> [descending].</param>
        /// <param name="userName">Name of the user.</param>
        /// <returns></returns>
        public List<Order> GetListForPagination(int page, int itemsOnPage, bool descending, string userName)
        {
            using (GeneralContext _db = new GeneralContext())
            {

                    if (descending == true)
                    {
                        var listForPagination = _db.Orders.Include("User")
                            .OrderBy(c => c.OrderId)
                            .Where(p => p.user.LoginName == userName)
                            .Skip((page - 1) * itemsOnPage)
                            .Take(itemsOnPage)
                            .ToList();

                        return listForPagination;
                    }
                    else
                    {
                        var listForPagination = _db.Orders.Include("User")
                            .OrderBy(c=>c.OrderId)
                            .Where(p => p.user.LoginName == userName)
                            .Skip((page - 1) * itemsOnPage)
                            .Take(itemsOnPage)
                            .ToList();

                        return listForPagination;
                    }


            }
        }
    }
}
